using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;


/// <summary>
/// 用于防止大量计算导致主线程卡帧
/// </summary>
public class 后台管理 : 单例_基础管理器<后台管理>
{
    private Thread 线程;
    private List<Thread> 多线程 = new List<Thread>();
    public 后台管理()
    {
        //初始化
        线程 = new Thread(() =>后台线程());
        线程.IsBackground = true;
        线程.Start();

        帧更新控制器.获取实例.开启携程(主线程());
    }

    private interface I事件属性 {
        void 调用();
        void 回调();
    }
    public class 委托类型<T> : I事件属性
    {
        public delegate T 事件委托();
        public 事件委托 事件;
        public Action<T> 完成后;
        public T 返回参数;
        public 委托类型(事件委托 事件,Action<T> 完成后)
        {
            this.事件 += 事件;
            this.完成后 += 完成后;
        }

        public void 调用() => 返回参数=事件();
        public void 回调() => 完成后(返回参数);
    }
    public class 委托类型 : I事件属性
    {
        public Action 事件;
        public Action 完成后;
        public 委托类型(Action 事件, Action 完成后)
        {
            this.事件 += 事件;
            if (完成后 != null) 
                this.完成后 += 完成后;
        }

        public void 调用() => 事件?.Invoke();
        public void 回调() => 完成后?.Invoke();
    }

    private Stack<I事件属性> 委托集合 = new Stack<I事件属性>();
    private Stack<I事件属性> 完成集合 = new Stack<I事件属性>();

    private void 后台线程()
    {
        //Action
        List<Thread> 移除 = new List<Thread>();
        while (true)
        {
            foreach (var item in 多线程)
            {
                if (!item.IsAlive)
                    移除.Add(item);
            }

            foreach (var item in 移除)
                多线程.Remove(item);

            if (委托集合.Count != 0)
            {
                for (int i = 0; i < 委托集合.Count; i++)
                {
                    I事件属性 等待调用 = 委托集合.Pop();
                    Thread 新线程 = new Thread(等待调用.调用);
                    新线程.IsBackground = true;
                    新线程.Start();
                    多线程.Add(新线程);
                    完成集合.Push(等待调用);
                }
            }
            else
                凌依.工具库.时间.延时执行(3);
        }
    }

    private IEnumerator 主线程()
    {
        while (true)
        {
            if (完成集合.Count != 0)
                for (int i = 0; i < 完成集合.Count; i++)
                    完成集合.Pop().回调();
            yield return 0;
        }
    }

    /// <summary>
    /// 仅限于数据处理,涉及Unity组件的代码直接报错
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="要做的事"></param>
    /// <param name="完成后">完成后的回调函数</param>
    public void 添加后台委托<T>(委托类型<T>.事件委托 要做的事,Action<T> 完成后)
    {
        委托集合.Push(new 委托类型<T>(要做的事, 完成后));
    }
    public void 添加后台委托(Action 要做的事, Action 完成后)
    {
        委托集合.Push(new 委托类型(要做的事, 完成后));
    }
}
